`include "mycpu.h"

module EXE_stage(
    input                          clk           ,
    input                          reset         ,
    //allowin
    input                          ms_allowin    ,
    input                          ms_will_to_ws ,
    output                         es_allowin    ,
    //from ds
    input                          ds_to_es_valid,
    input  [`DS_TO_ES_BUS_WD -1:0] ds_to_es_bus  ,//136

    // input                           ws_to_es_ex,
    // input                           ms_to_es_ex,
    input                           ms_to_es_data_alok2,
    input                           ms_to_es_data_alok,
    //to fs
    output  [`ES_FLUSH_BUS_WD -1:0] es_flush_bus,
    //to ds
    output [`ES_TO_DS_BUS_WD   -1:0] es_to_ds_bus ,//
    //to ms
    output                         es_to_ms_valid,
    output                         es_to_ms_cancel_first_back,
    output [`ES_TO_MS_BUS_WD -1:0] es_to_ms_bus  ,//71
    //to_rfo
    //output [`ES_TO_RF_BUS_WD -1:0]  es_to_rfo_bus  ,
    //
    input                           ws_to_es_flush,
    input                           ms_to_es_flush,
    //to TH test_hazard
    output [`ES_TO_TH_BUS_WD -1:0]    es_to_th_bus  ,
    input                             cr_flush_o,
    // data sram interface
    output        data_sram_req   ,
    output        data_sram_wr,
    output [ 1:0] data_sram_size,
    output [ 7:0] data_sram_wstrb  ,
    output [63:0] data_sram_addr ,
    output [63:0] data_sram_wdata,
    input         data_sram_addr_ok,
    input         data_sram_data_ok,
    input  [63:0] data_sram_rdata
);


reg  [`DS_TO_ES_BUS_WD -1:0] ds_to_es_bus_r;
reg         es_valid      ;
reg         addr_alok;
reg         cancel_first_back; 
reg         just_one_work;
reg   [1:0] count;
reg         req;

wire        req_can;
wire        count_add;
wire        count_sub;
wire        data_alok2;
wire        data_alok;
assign  data_alok = ms_to_es_data_alok;
assign  data_alok2= ms_to_es_data_alok2;


wire        addr_is_same;
wire        es_ready_go   ;
wire        es_bd;
wire        load_or_store_op;
wire        es_load_op    ;
wire        es_src1_is_sa ;  
wire        es_src1_is_pc ;
wire        es_src2_is_imm_0;
wire        es_src2_is_imm; 
wire        es_src2_is_4  ;
wire        es_gr_we      ;
wire        es_mem_we     ;
wire        alu_stall;
wire        es_res_from_mem;
// wire        ds_to_es_ex;
wire        es_can_ov;
wire        es_ades;
wire        es_adel;
// wire        es_ex;
wire        es_ov;
wire        es_bp;
wire        op_sh;
wire        op_sb;
wire        op_sw;
wire        op_lw;
wire        op_lh;
wire        op_lhu;
wire        mem_op;
wire        op_lb;
wire        op_lbu;

wire [7:0]  sram_wen;
wire [4:0]  es_dest       ;
wire [3:0]  es_mem_op;
wire [6:0]  es_load_op_clear;
wire [15:0] es_alu_op     ;
wire [31:0] es_imm        ;
wire [63:0] es_rs1_value   ;
wire [63:0] es_rs2_value   ;
wire [63:0] es_pc         ;
wire [63:0] es_alu_src1   ;
wire [63:0] es_alu_src2   ;
wire [63:0] es_alu_result ;

wire [31:0] es_inst;
wire        es_src2_rv32_sa;
wire        es_src2_rv64_sa;
wire        src1_is_pc;
wire        src2_is_imm;
wire        src2_is_4;
wire        op_sd;
wire        op_lwu;
wire        op_ld;
wire        es_0x7b;

//
wire[11:0] csr_addr;
wire[4:0] es_zimm;
wire        es_int;
wire        es_ex;
wire  es_csrrw ; 
wire  es_csrrs ;
wire  es_csrrc ;
wire  es_csrrwi;
wire  es_csrrsi;
wire  es_csrrci;
wire  es_mret;
wire  es_op_csr;


reg  es_flush_reg;
wire [63:0] es_bpu_pc;
wire [63:0] es_br_target;

wire        es_flush;
assign es_flush = es_bpu_pc != es_br_target && es_valid;
assign es_flush_bus = {es_flush , es_br_target};
assign es_op_csr =   es_csrrw   ||  es_csrrs  ||  es_csrrc  ||  es_csrrwi ||  es_csrrsi ||  es_csrrci ;


//这个错误我弄了好久就因为变成4位宽
// wire [4:0]  es_op_eret;

//修改
//去掉非对齐访问指令
//修改alu以便于支持64为运算
//去掉乘法与除法
//注意alu_src的不同RV64与MIPS32的区别



assign {
                        es_int,
                        es_ex,
                        es_mret,
                        es_csrrw ,
                        es_csrrs ,
                        es_csrrc ,
                        es_csrrwi,
                        es_csrrsi,
                        es_csrrci,                        
                        es_zimm,
                        csr_addr,
        es_0x7b,
        es_mem_op, //360:358
       es_load_op_clear,//357:353
       es_alu_op      ,  //352:337
       es_load_op     ,  //336  //少了load_op造成后面�?系列的Z
       es_src2_rv64_sa     ,//335
       es_src2_rv32_sa     ,//334
       es_src1_is_pc  ,  //333:333
       es_src2_is_imm ,  //332:332
       es_src2_is_4   ,  //331:331
       es_gr_we       ,  //330:330
       es_mem_we      ,  //229:229
       es_dest        ,  //228:224
       es_imm         ,  //223:129
       es_rs1_value    ,  //191 : 128
       es_rs2_value    ,  //127 :64
       es_inst         ,
       es_bpu_pc        ,
       es_br_target    ,
       es_pc               //63 :0
       } = ds_to_es_bus_r;


//

assign es_to_ms_bus = { 
                        es_int,
                        es_ex,
                        es_mret,
                        es_csrrw ,
                        es_csrrs ,
                        es_csrrc ,
                        es_csrrwi,
                        es_csrrsi,
                        es_csrrci,                        
                        es_zimm,
                        csr_addr,
                        es_0x7b,
                        es_load_op, //141
                        load_or_store_op,//140
                        es_load_op_clear,//139:135
                        es_res_from_mem,  //134:134
                        es_gr_we       ,  //133:133
                        es_dest        ,  //132:128
                        es_rs1_value   ,
                        es_alu_result  ,  //127:64
                        es_inst         ,
                        es_pc             //63:0
                      };

//
assign es_to_th_bus = { 
                        es_op_csr, //8:8
                        es_load_op,//7:7
                        es_valid ,//6:6
                         es_gr_we ,  //5:5
                        es_dest    //4:0
};
assign es_to_ds_bus = {es_load_op,//71:71
                       es_valid ,//70:70  
                       es_gr_we,//~es_inst_lw,//69:69
                       es_dest,         //68:64
                       es_alu_result    //63:0
                       };

assign count_add = data_sram_req && data_sram_addr_ok && !data_sram_data_ok;
assign count_sub = data_sram_data_ok && !( data_sram_req && data_sram_addr_ok);

assign es_res_from_mem = es_load_op;


assign load_or_store_op = mem_op || es_load_op;
assign es_ready_go    = load_or_store_op && (data_sram_req && data_sram_addr_ok ||  addr_alok ) && ~alu_stall
                      || !alu_stall   && ~es_load_op    &&  ~mem_op 
                      || es_ex && es_valid; 
                     
assign es_allowin     = !es_valid || es_ready_go && ms_allowin ;
assign es_to_ms_valid =  es_valid && es_ready_go;
always @(posedge clk) begin
    if (reset ||cr_flush_o || es_flush && es_ready_go ||es_flush_reg && es_ready_go ) begin
        es_valid <= 1'b0;
    end
    else if (es_allowin) begin
        es_valid <= ds_to_es_valid;
    end

    if (ds_to_es_valid && es_allowin) begin
        ds_to_es_bus_r <= ds_to_es_bus;
    end

    if (reset || cr_flush_o || es_ready_go) begin
        es_flush_reg <= 1'b0;
    end
    else if (!es_ready_go && es_valid && es_flush) begin
        es_flush_reg <= 1'b1;
    end
end

always @(posedge clk) begin

  if (ms_allowin && es_ready_go || reset || cr_flush_o) begin
        addr_alok <= 1'b0;
    end
    else if (data_sram_addr_ok && data_sram_req ) begin
        addr_alok <= 1'b1;
    end

    if (reset || count == 2'b0 && !count_add || count == 2'h1 && count_sub ) begin
        cancel_first_back <= 1'b0;
    end
    else if ( cr_flush_o && !(  count == 2'b0 && !count_add || count == 2'h1 && count_sub)) begin
        cancel_first_back <= 1'b1;
    end

    if (reset) begin
        count <= 2'b0;
    end
    else if (count_add) begin
        count <= count + 1'b1;
    end
    else if (count_sub)begin
        count <= count -1'b1;
    end
  
  
    if (reset || es_ready_go && !ms_allowin  || cr_flush_o || !load_or_store_op || data_sram_req && data_sram_addr_ok ) begin
        req <= 1'b0;
    end
    else if (req_can ) begin
        req <= 1'b1;
    end
  
end
assign es_to_ms_cancel_first_back = cancel_first_back;
// assign req_can = (mem_op || es_load_op) 
//                 && (!es_ready_go && !ms_allowin || !es_ready_go && ms_allowin || es_ready_go && ms_allowin) 
//                 && (!data_alok2 )  
//                 && (!data_alok || data_alok && count == 2'b0) 
//                 && !cancel_first_back
//                 && !alu_stall
//                 && es_valid
//                 && ms_allowin;
assign req_can = (mem_op || es_load_op)  && ms_allowin && !es_ex && !es_int && !ws_to_es_flush && !ms_to_es_flush;


assign es_alu_src1 = es_src1_is_pc    ? es_pc:
                                      es_rs1_value;
                     
assign es_alu_src2 = es_src2_is_imm   ? {{32{es_imm[31]}}, es_imm} : 
                     es_src2_is_4     ? 64'h4 :
                                        es_rs2_value;
                        

alu u_alu(
    .clk        (clk            ),
    .reset      (reset          ),
    .alu_can_ov (es_can_ov      ),
    .alu_op     (es_alu_op    ),
    .alu_src1   (es_alu_src1  ),//两个es_alu_src2
    .alu_src2   (es_alu_src2  ),//Error_05
    .alu_result (es_alu_result),
    .alu_stall  (alu_stall),
    .alu_ex     (es_ov)
    );


assign mem_op       = op_sw || op_sh || op_sb || op_sd ;

assign op_sw        = es_mem_op[0];
assign op_sh        = es_mem_op[1];
assign op_sb        = es_mem_op[2];
assign op_sd        = es_mem_op[3];
assign op_lw        = es_load_op_clear[ 0];
assign op_lb        = es_load_op_clear[ 1];
assign op_lbu       = es_load_op_clear[ 2];
assign op_lh        = es_load_op_clear[ 3];
assign op_lhu       = es_load_op_clear[ 4];
assign op_lwu       = es_load_op_clear[ 5];
assign op_ld        = es_load_op_clear[ 6];

//下面这一大串& 2'h2 与 && 2'h2 不一样
//& 2'h2 可以得2
// && 2'h2 在上面得情况下会是1而不是期待得2
assign data_sram_size = ({2{op_lw || op_sw }}              & 2'h2)
                      | ({2{op_sh || op_lhu   || op_sh }}  & 2'h1)
                      | ({2{op_lb || op_lbu   || op_sb }}  & 2'h0);
                      
assign es_adel      = op_lw  && es_alu_result[1:0] != 2'b0
                   || (op_lh  || op_lhu  ) && es_alu_result [0] != 1'b0;
assign es_ades      = op_sw  && es_alu_result[1:0] != 2'b0   || op_sh && es_alu_result [0] != 1'b0;

// assign es_ex        = es_valid && (ds_to_es_ex || es_adel || es_ades  || es_ov);
wire  [2:0] offset;
wire  [7:0] sel;
assign   offset = es_alu_result[2:0];
decoder_3_8   u_dec1(.in(offset),    .out(sel));

wire  [63:0] wdata;
// assign wdata    = ({64{op_sb & sel[3'h0]} }  & {8{es_rs2_value[07:00]}} )
//                 | ({64{op_sb & sel[3'h1]} }  & {8{es_rs2_value[15:08]}} )
//                 | ({64{op_sb & sel[3'h2]} }  & {8{es_rs2_value[23:16]}} )
//                 | ({64{op_sb & sel[3'h3]} }  & {8{es_rs2_value[31:24]}} )
//                 | ({64{op_sb & sel[3'h4]} }  & {8{es_rs2_value[39:32]}} )
//                 | ({64{op_sb & sel[3'h5]} }  & {8{es_rs2_value[47:40]}} )
//                 | ({64{op_sb & sel[3'h6]} }  & {8{es_rs2_value[55:48]}} )
//                 | ({64{op_sb & sel[3'h7]} }  & {8{es_rs2_value[63:56]}} )
//                 | ({64{op_sh & sel[3'h0]}}   & {4{es_rs2_value[15:00]}})
//                 | ({64{op_sh & sel[3'h2]}}   & {4{es_rs2_value[31:16]}})
//                 | ({64{op_sh & sel[3'h4]}}   & {4{es_rs2_value[48:32]}})
//                 | ({64{op_sh & sel[3'h6]}}   & {4{es_rs2_value[63:49]}})
//                 | ({64{op_sw & sel[3'h0]}}   & {2{es_rs2_value[31:00]}})
//                 | ({64{op_sw & sel[3'h4]}}   & {2{es_rs2_value[63:32]}})
//                 | ({64{op_sd}}                & es_rs2_value           );

assign wdata    = ({64{op_sb  } }  & {8{es_rs2_value[07:00]}} )
                | ({64{op_sh  }}   & {4{es_rs2_value[15:00]}})
                | ({64{op_sw  }}   & {2{es_rs2_value[31:00]}})
                | ({64{op_sd  }}   & es_rs2_value           );

assign sram_wen = ({8{op_sb & sel[3'h0]} }  & 8'b0000_0001 )
                | ({8{op_sb & sel[3'h1]} }  & 8'b0000_0010 )
                | ({8{op_sb & sel[3'h2]} }  & 8'b0000_0100 )
                | ({8{op_sb & sel[3'h3]} }  & 8'b0000_1000 )
                | ({8{op_sb & sel[3'h4]} }  & 8'b0001_0000 )
                | ({8{op_sb & sel[3'h5]} }  & 8'b0010_0000 )
                | ({8{op_sb & sel[3'h6]} }  & 8'b0100_0000 )
                | ({8{op_sb & sel[3'h7]} }  & 8'b1000_0000 )
                | ({8{op_sh & sel[3'h0]}}   & 8'b0000_0011 )
                | ({8{op_sh & sel[3'h2]}}   & 8'b0000_1100)
                | ({8{op_sh & sel[3'h4]}}   & 8'b0011_0000)
                | ({8{op_sh & sel[3'h6]}}   & 8'b1100_0000)
                | ({8{op_sw & sel[3'h0]}}   & 8'h0f       )
                | ({8{op_sw & sel[3'h4]}}   & 8'hf0       )
                | ({8{op_sd}}               & 8'hff     );
// assign sram_wen = ({8{op_sd}}  & 8'b1111_1111)
                // | ({8{op_sw}}  & 8'b0000_1111)
                // | ({8{op_sh}}  & 8'b0000_0011)
                // | ({8{op_sb}}  & 8'b0000_0001);

assign data_sram_req = req && es_valid;

                                                
wire [7:0]  wstrb;
assign data_sram_wr    =  mem_op && es_valid && !es_ex && !es_int && !ws_to_es_flush && !ms_to_es_flush && !es_flush && !es_flush_reg ;
assign wstrb   =es_mem_we&&es_valid && data_sram_wr   ? sram_wen : 8'h00;
assign data_sram_wstrb = wstrb;
assign data_sram_addr  = data_sram_req ? es_alu_result : 63'b0;
assign data_sram_wdata = wdata;

endmodule
